home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / LanguageSelector / gtk / GtkLanguageSelector.py < prev    next >
Encoding:
Python Source  |  2009-05-07  |  33.5 KB  |  870 lines

  1. # (c) 2005 Canonical
  2. # Author: Michael Vogt <michael.vogt@ubuntu.com>
  3. #
  4. # Released under the GPL
  5. #
  6.  
  7. import pygtk
  8. pygtk.require('2.0')
  9. import gtk
  10. import gtk.gdk
  11. import gtk.glade
  12. import pango
  13. import gobject
  14. import os.path
  15. import string
  16. import warnings
  17. warnings.filterwarnings("ignore", "apt API not stable yet", FutureWarning)
  18. import apt
  19. import apt_pkg
  20. import os.path
  21. import shutil
  22. import subprocess
  23. import thread
  24. import time
  25. import gettext
  26. import sys
  27. import tempfile
  28. import pwd
  29. import grp
  30. import os
  31.  
  32. from gettext import gettext as _
  33.  
  34.  
  35. (LIST_LANG,                     # language (i18n/human-readable)
  36.  LIST_LANG_INFO                 # the short country code (e.g. de, pt_BR)
  37.  ) = range(2)
  38.  
  39. (COMBO_LANGUAGE,
  40.  COMBO_CODE) = range(2)
  41.  
  42.  
  43.  
  44. from LanguageSelector.gtk.SimpleGladeApp import SimpleGladeApp
  45. from LanguageSelector.LocaleInfo import LocaleInfo
  46. from LanguageSelector.LanguageSelector import *
  47. from LanguageSelector.ImSwitch import ImSwitch
  48.  
  49.  
  50. def xor(a,b):
  51.     " helper to simplify the reading "
  52.     return a ^ b
  53.  
  54. def blockSignals(f):
  55.     " decorator to ensure that the signals are blocked "
  56.     def wrapper(*args, **kwargs):
  57.         args[0]._blockSignals = True
  58.         res = f(*args, **kwargs)
  59.         args[0]._blockSignals = False
  60.         return res
  61.     return wrapper
  62.  
  63. def honorBlockedSignals(f):
  64.     " decorator to ensure that the signals are blocked "
  65.     def wrapper(*args, **kwargs):
  66.         if args[0]._blockSignals:
  67.             return
  68.         res = f(*args, **kwargs)
  69.         return res
  70.     return wrapper
  71.  
  72. def insensitive(f):
  73.     """
  74.     decorator to ensure that a given function is run insensitive
  75.     warning: this will not stack well so don't use it for nested
  76.     stuff (a @insensitive func calling a @insensitve one)
  77.     """
  78.     def wrapper(*args, **kwargs):
  79.         args[0].setSensitive(False)
  80.         res = f(*args, **kwargs)
  81.         args[0].setSensitive(True)
  82.     return wrapper
  83.  
  84.  
  85.  
  86. # intervals of the start up progress
  87. # 3x caching and menu creation
  88. STEPS_UPDATE_CACHE = [33, 66, 100]
  89.  
  90. class GtkProgress(apt.OpProgress):
  91.     def __init__(self, host_window, progressbar, parent,
  92.                  steps=STEPS_UPDATE_CACHE):
  93.         # used for the "one run progressbar"
  94.         self.steps = steps[:]
  95.         self.base = 0
  96.         self.old = 0
  97.         self.next = int(self.steps.pop(0))
  98.  
  99.         self._parent = parent
  100.         self._window = host_window
  101.         self._progressbar = progressbar
  102.         self._window.realize()
  103.         host_window.window.set_functions(gtk.gdk.FUNC_MOVE)
  104.         self._window.set_transient_for(parent)
  105.     def update(self, percent):
  106.         #print percent
  107.         #print self.Op
  108.         #print self.SubOp
  109.         self._window.show()
  110.         self._parent.set_sensitive(False)
  111.         # if the old percent was higher, a new progress was started
  112.         if self.old > percent:
  113.             # set the borders to the next interval
  114.             self.base = self.next
  115.             try:
  116.                 self.next = int(self.steps.pop(0))
  117.             except:
  118.                 pass
  119.         progress = self.base + percent/100 * (self.next - self.base)
  120.         self.old = percent
  121.         self._progressbar.set_fraction(progress/100.0)
  122.         while gtk.events_pending():
  123.             gtk.main_iteration()
  124.     def done(self):
  125.         self._parent.set_sensitive(True)
  126.     def hide(self):
  127.         self._window.hide()
  128.  
  129. class GtkLanguageSelector(LanguageSelectorBase,  SimpleGladeApp):
  130.  
  131.     def __init__(self, datadir, options):
  132.         LanguageSelectorBase.__init__(self, datadir)
  133.         SimpleGladeApp.__init__(self,
  134.                                 datadir+"/data/LanguageSelector.glade",
  135.                                 domain="language-selector")
  136.  
  137.         self.is_admin = grp.getgrnam("admin")[2] in os.getgroups()
  138.         # see if we have any other human users on this system
  139.         self.has_other_users = False
  140.         num = 0
  141.         for l in pwd.getpwall():
  142.             if l.pw_uid >= 500 and l.pw_uid < 65534:
  143.                 num += 1
  144.             if num >= 2:
  145.                 self.has_other_users = True
  146.                 break
  147.         
  148.         #build the comboboxes (with model)
  149.         combo = self.combobox_system_language
  150.         model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
  151.         cell = gtk.CellRendererText()
  152.         combo.pack_start(cell, True)
  153.         combo.add_attribute(cell, 'text', COMBO_LANGUAGE)
  154.         combo.set_model(model)
  155.         self.combo_syslang_dirty = False
  156.  
  157.         combo = self.combobox_user_language
  158.         model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
  159.         cell = gtk.CellRendererText()
  160.         combo.pack_start(cell, True)
  161.         combo.add_attribute(cell, 'text', COMBO_LANGUAGE)
  162.         combo.set_model(model)
  163.         self.combo_userlang_dirty = False
  164.         self.imSwitch = ImSwitch()
  165.         self.options = options
  166.         self._blockSignals = False
  167.  
  168.         # build the treeview
  169.         self.setupTreeView()
  170.         self.updateLanguageView()
  171.         self.updateUserDefaultCombo()
  172.         self.updateSystemDefaultCombo()
  173.         self.check_input_methods()
  174.         self.updateSyncButton()
  175.         
  176.         # apply button
  177.         self.button_apply.set_sensitive(False)
  178.  
  179.         # show it
  180.         self.window_main.show()
  181.         self.setSensitive(False)
  182.  
  183.         # check if the package list is up-to-date
  184.         if not self._cache.havePackageLists:
  185.             d = gtk.MessageDialog(parent=self.window_main,
  186.                                   flags=gtk.DIALOG_MODAL,
  187.                                   type=gtk.MESSAGE_INFO,
  188.                                   buttons=gtk.BUTTONS_CANCEL)
  189.             d.set_markup("<big><b>%s</b></big>\n\n%s" % (
  190.                 _("No language information available"),
  191.                 _("The system does not have information about the "
  192.                   "available languages yet. Do you want to perform "
  193.                   "a network update to get them now? ")))
  194.             d.set_title=("")
  195.             d.add_button(_("_Update"), gtk.RESPONSE_YES)
  196.             res = d.run()
  197.             d.destroy()
  198.             if res == gtk.RESPONSE_YES:
  199.                 self.setSensitive(False)
  200.                 self.update()
  201.                 self.updateLanguageView()
  202.                 self.setSensitive(True)
  203.  
  204.         # see if something is missing
  205.         if self.options.verify_installed:
  206.             self.verifyInstalledLangPacks()
  207.  
  208.         if not self.imSwitch.available():
  209.             self.checkbutton_enable_input_methods.set_sensitive(False)
  210.         self.setSensitive(True)
  211.  
  212.     def setSensitive(self, value):
  213.         if value:
  214.             self.window_main.set_sensitive(True)
  215.             self.window_main.window.set_cursor(None)
  216.         else:
  217.             self.window_main.set_sensitive(False)
  218.             self.window_main.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
  219.         while gtk.events_pending():
  220.             gtk.main_iteration()
  221.  
  222.     def runAsRoot(self, userCmd):
  223.         " run the given command as root using gksu "
  224.         cmd = ["/usr/bin/gksu", 
  225.                "--desktop", 
  226.                "/usr/share/applications/language-selector.desktop", 
  227.                "--"]
  228.         ret = subprocess.call(cmd+userCmd)
  229.         return (ret == 0)
  230.  
  231.     @blockSignals
  232.     def updateSyncButton(self):
  233.         " check if the sync languages button should be enabled or not "
  234.         button = self.checkbutton_sync_languages
  235.         combo = self.combobox_system_language
  236.         # no admin user, gray out
  237.         if self.is_admin == False:
  238.             button.set_active(False)
  239.             button.set_sensitive(False)
  240.             combo.set_sensitive(False)
  241.             return
  242.         # admin user, check stuff
  243.         button.set_sensitive(True)
  244.         combo.set_sensitive(True)
  245.         # do not enable the keep the same button if the system has other
  246.         # users or if the language settings are inconsistent already
  247.         userlang = self.combobox_user_language.get_active()
  248.         systemlang = self.combobox_system_language.get_active()
  249.         if (not self.has_other_users and userlang == systemlang):
  250.             button.set_active(True)
  251.         else:
  252.             button.set_active(False)
  253.  
  254.     def setupTreeView(self):
  255.         """ do all the treeview setup here """
  256.         def toggle_cell_func(column, cell, model, iter):
  257.             langInfo = model.get_value(iter, LIST_LANG_INFO)
  258.  
  259.             # check for active and inconsitent 
  260.             inconsistent = langInfo.inconsistent
  261.             #if inconsistent:
  262.             #    print "%s is inconsistent" % langInfo.language
  263.  
  264.             cell.set_property("active", langInfo.fullInstalled)
  265.             cell.set_property("inconsistent", inconsistent)
  266.             
  267.         def lang_view_func(cell_layout, renderer, model, iter):
  268.             langInfo = model.get_value(iter, LIST_LANG_INFO)
  269.             inconsistent = langInfo.inconsistent
  270.             if (langInfo.changes) :
  271.                 markup = "<b>%s</b>" % langInfo.language
  272.             else:
  273.                 markup = "%s" % langInfo.language
  274.             renderer.set_property("markup", markup)
  275.  
  276.         renderer = gtk.CellRendererText()
  277.         column = gtk.TreeViewColumn(_("Language"), renderer, text=LIST_LANG)
  278.         column.set_property("expand", True)
  279.         column.set_cell_data_func (renderer, lang_view_func)
  280.         self.treeview_languages.append_column(column)
  281.  
  282.         renderer= gtk.CellRendererToggle()
  283.         renderer.connect("toggled", self.on_toggled)
  284.         column = gtk.TreeViewColumn(_("Installed"), renderer)
  285.         column.set_cell_data_func (renderer, toggle_cell_func)
  286.         self.treeview_languages.append_column(column)
  287.         # build the store
  288.         self._langlist = gtk.ListStore(str, gobject.TYPE_PYOBJECT)
  289.         self.treeview_languages.set_model(self._langlist)
  290.  
  291.     def _get_langinfo_on_cursor(self):
  292.         (path, column) = self.treeview_languages.get_cursor ()
  293.         if not path:
  294.             return None
  295.         iter = self._langlist.get_iter(path)
  296.         langInfo = self._langlist.get_value(iter, LIST_LANG_INFO)
  297.         return langInfo
  298.  
  299.     # details checkboxes
  300.     def on_checkbutton_fonts_clicked(self, button):
  301.         if self.block_toggle: return
  302.         langInfo = self._get_langinfo_on_cursor()
  303.         langInfo.languagePkgList["languageSupportFonts"].doChange = not langInfo.languagePkgList["languageSupportFonts"].doChange
  304.         self.check_status()
  305.         self.treeview_languages.queue_draw()
  306.         #self.debug_pkg_status()
  307.     def on_checkbutton_input_methods_clicked(self, button):
  308.         if self.block_toggle: return
  309.         langInfo = self._get_langinfo_on_cursor()
  310.         langInfo.languagePkgList["languageSupportInputMethods"].doChange = not langInfo.languagePkgList["languageSupportInputMethods"].doChange
  311.         self.check_status()
  312.         self.treeview_languages.queue_draw()
  313.         #self.debug_pkg_status()
  314.     def on_checkbutton_writing_aids_clicked(self, button):
  315.         if self.block_toggle: return
  316.         langInfo = self._get_langinfo_on_cursor()
  317.         langInfo.languagePkgList["languageSupportWritingAids"].doChange = not langInfo.languagePkgList["languageSupportWritingAids"].doChange
  318.         self.check_status()
  319.         self.treeview_languages.queue_draw()
  320.         #self.debug_pkg_status()
  321.     def on_checkbutton_basic_translations_clicked(self, button):
  322.         if self.block_toggle: return
  323.         langInfo = self._get_langinfo_on_cursor()
  324.         langInfo.languagePkgList["languagePack"].doChange = not langInfo.languagePkgList["languagePack"].doChange
  325.         self.check_status()
  326.         self.treeview_languages.queue_draw()
  327.         #self.debug_pkg_status()
  328.     def on_checkbutton_extra_translations_clicked(self, button):
  329.         if self.block_toggle: return
  330.         langInfo = self._get_langinfo_on_cursor()
  331.         langInfo.languagePkgList["languageSupportTranslations"].doChange = not langInfo.languagePkgList["languageSupportTranslations"].doChange
  332.         self.check_status()
  333.         self.treeview_languages.queue_draw()
  334.         #self.debug_pkg_status()
  335.     def on_checkbutton_extra_clicked(self, button):
  336.         if self.block_toggle: return
  337.         langInfo = self._get_langinfo_on_cursor()
  338.         langInfo.languagePkgList["languageSupportExtra"].doChange = not langInfo.languagePkgList["languageSupportExtra"].doChange
  339.         self.check_status()
  340.         self.treeview_languages.queue_draw()
  341.         #self.debug_pkg_status()
  342.  
  343.     # the global toggle
  344.     def on_toggled(self, renderer, path_string):
  345.         """ called when on install toggle """
  346.         iter = self._langlist.get_iter_from_string(path_string)
  347.         langInfo = self._langlist.get_value(iter, LIST_LANG_INFO)
  348.  
  349.         # special handling for inconsistent state
  350.         if langInfo.inconsistent :
  351.             for pkg in langInfo.languagePkgList.values() :
  352.                 if (pkg.available and not pkg.installed) : 
  353.                     pkg.doChange = True
  354.         elif langInfo.fullInstalled :
  355.             for pkg in langInfo.languagePkgList.values() :
  356.                 if (pkg.available) :
  357.                     if (not pkg.installed and pkg.doChange) :
  358.                         pkg.doChange = False
  359.                     elif (pkg.installed and not pkg.doChange) :
  360.                         pkg.doChange = True
  361.         else :
  362.             for pkg in langInfo.languagePkgList.values() :
  363.                 if (pkg.available) :
  364.                     if (pkg.installed and pkg.doChange) :
  365.                         pkg.doChange = False
  366.                     elif (not pkg.installed and not pkg.doChange) :
  367.                         pkg.doChange = True
  368.  
  369.         self.check_status()
  370.         self.treeview_languages.queue_draw()
  371.         #self.debug_pkg_status()
  372.  
  373.     def on_treeview_languages_cursor_changed(self, treeview):
  374.         #print "on_treeview_languages_cursor_changed()"
  375.         langInfo = self._get_langinfo_on_cursor()
  376.         for (button, attr) in ( 
  377.               ("checkbutton_basic_translations", langInfo.languagePkgList["languagePack"]),
  378.               ("checkbutton_extra_translations", langInfo.languagePkgList["languageSupportTranslations"]),
  379.               ("checkbutton_writing_aids", langInfo.languagePkgList["languageSupportWritingAids"]),
  380.               ("checkbutton_input_methods", langInfo.languagePkgList["languageSupportInputMethods"]),
  381.               ("checkbutton_extra", langInfo.languagePkgList["languageSupportExtra"]),
  382.               ("checkbutton_fonts", langInfo.languagePkgList["languageSupportFonts"])  ):
  383.             self.block_toggle = True
  384.             if ((attr.installed and not attr.doChange) or (not attr.installed and attr.doChange)) :
  385.                 getattr(self, button).set_active(True)
  386.             else :
  387.                 getattr(self, button).set_active(False)
  388.             getattr(self, button).set_sensitive(attr.available)
  389.             self.block_toggle = False
  390.             #self.debug_pkg_status()
  391.  
  392.     def on_button_install_remove_languages_clicked(self, widget):
  393.         self.window_installer.show()
  394.  
  395.     def debug_pkg_status(self):
  396.         langInfo = self._get_langinfo_on_cursor()
  397.         for pkg in langInfo.languagePkgList.items() :
  398.             print ("%s, available: %s, installed: %s, doChange: %s" % (pkg[0], pkg[1].available, pkg[1].installed, pkg[1].doChange))
  399.         print ("inconsistent? : %s" % langInfo.inconsistent)
  400.  
  401.     def check_status(self):
  402.         changed = False
  403.         countInstall = 0
  404.         countRemove = 0
  405.         for (lang, langInfo) in self._langlist:
  406.             if langInfo.changes:
  407.                 changed = True
  408.                 for item in langInfo.languagePkgList.values():
  409.                     if item.doChange:
  410.                         if item.installed:
  411.                             countRemove = countRemove + 1
  412.                         else:
  413.                             countInstall = countInstall + 1
  414.         #print "%d to install, %d to remove" % (countInstall, countRemove)
  415.         textInstall = gettext.ngettext("%d to install", "%d to install", countInstall) % countInstall
  416.         textRemove = gettext.ngettext("%d to remove", "%d to remove", countRemove) % countRemove
  417.         if countRemove == 0 and countInstall == 0: 
  418.             self.label_install_remove.set_text("")
  419.         elif countRemove == 0: 
  420.             self.label_install_remove.set_text(textInstall)
  421.         elif countInstall == 0: 
  422.             self.label_install_remove.set_text(textRemove)
  423.         # Translators: this string will concatenate the "%n to install" and "%n to remove" strings, you can replace the comma if you need to.
  424.         else: 
  425.             self.label_install_remove.set_text(_("%s, %s") % (textInstall, textRemove))
  426.         
  427.         if changed:
  428.             self.button_apply.set_sensitive(True)
  429.         else:
  430.             self.button_apply.set_sensitive(False)
  431.  
  432.     @honorBlockedSignals
  433.     @insensitive
  434.     def on_combobox_system_language_changed(self, widget):
  435.         #print "on_combobox_system_language_changed()"
  436.         if self.writeSystemDefaultLang():
  437.             # queue a restart of gdm (if it is runing) to make the new
  438.             # locales usable
  439.             gdmscript = "/etc/init.d/gdm"
  440.             if os.path.exists("/var/run/gdm.pid") and os.path.exists(gdmscript):
  441.                 self.runAsRoot(["invoke-rc.d","gdm","reload"])
  442.         self.updateSystemDefaultCombo()
  443.         if self.checkbutton_sync_languages.get_active() == True:
  444.             self.combobox_user_language.set_active(self.combobox_system_language.get_active())
  445.             self.updateUserDefaultCombo()
  446.  
  447.     @honorBlockedSignals
  448.     @insensitive
  449.     def on_combobox_user_language_changed(self, widget):
  450.         #print "on_combobox_user_language_changed()"
  451.         self.check_input_methods()
  452.         self.writeUserDefaultLang()
  453.         self.updateUserDefaultCombo()
  454.         if self.checkbutton_sync_languages.get_active() == True:
  455.             self.combobox_system_language.set_active(self.combobox_user_language.get_active())
  456.             self.updateSystemDefaultCombo()
  457.  
  458.     @blockSignals
  459.     def check_input_methods(self):
  460.         """ check if the selected langauge has input method support
  461.             and set checkbutton_enable_input_methods accordingly
  462.         """
  463.         if not self.imSwitch.available():
  464.             return
  465.         # get current selected default language
  466.         combo = self.combobox_user_language
  467.         model = combo.get_model()
  468.         if combo.get_active() < 0:
  469.             return
  470.         (lang, code) = model[combo.get_active()]
  471.         # check if that has a im-switch config
  472.         active = self.imSwitch.enabledForLocale(code)
  473.         self.checkbutton_enable_input_methods.set_active(active)
  474.  
  475.     def writeInputMethodConfig(self):
  476.         """ 
  477.         write new input method defaults - currently we only support all_ALL
  478.         """
  479.         combo = self.combobox_user_language
  480.         model = combo.get_model()
  481.         if combo.get_active() < 0:
  482.             return
  483.         (lang, code) = model[combo.get_active()]
  484.         # check if we need to do something
  485.         new_value = self.checkbutton_enable_input_methods.get_active()
  486.         if self.imSwitch.enabledForLocale(code) != new_value:
  487.             if new_value:
  488.                 self.imSwitch.enable(code)
  489.             else:
  490.                 self.imSwitch.disable(code)
  491.             #self.showRebootRequired()
  492.             #self.checkReloginNotification()
  493.  
  494.     @honorBlockedSignals
  495.     def on_checkbutton_enable_input_methods_toggled(self, widget):
  496.         #print "on_checkbutton_enable_input_methods_toggled()"
  497.         active = self.checkbutton_enable_input_methods.get_active()
  498.         self.combo_userlang_dirty = True
  499.         self.setSensitive(False)
  500.         self.writeInputMethodConfig()
  501.         self.setSensitive(True)
  502.  
  503.     @honorBlockedSignals
  504.     def on_checkbutton_sync_languages_toggled(self, widget):
  505.         #print "on_checkbutton_sync_languages_toggled()"
  506.         if self.checkbutton_sync_languages.get_active() == True:
  507.             self.combobox_user_language.set_active(self.combobox_system_language.get_active())
  508.             self.updateSystemDefaultCombo()
  509.         
  510.     def build_commit_lists(self):
  511.         for (lang, langInfo) in self._langlist:
  512.             self._cache.tryChangeDetails(langInfo)
  513.         (to_inst, to_rm) = self._cache.getChangesList()
  514.         #print "inst: %s" % to_inst
  515.         #print "rm: %s" % to_rm
  516.         return (to_inst, to_rm)
  517.  
  518.     def verify_commit_lists(self, inst_list, rm_list):
  519.         """ verify if the selected package can actually be installed """
  520.         res = True
  521.         try:
  522.             for pkg in inst_list:
  523.                 if self._cache.has_key(pkg):
  524.                     self._cache[pkg].markInstall()
  525.             for pkg in rm_list:
  526.                 if self._cache.has_key(pkg):
  527.                     self._cache[pkg].markDelete()
  528.         except SystemError:
  529.             res = False
  530.  
  531.         # undo the selections
  532.         self._cache.clear()
  533.         if self._cache._depcache.BrokenCount != 0:
  534.             # undoing the selections was impossible, 
  535.             d = gtk.MessageDialog(parent=self.window_main,
  536.                                   flags=gtk.DIALOG_MODAL,
  537.                                   type=gtk.MESSAGE_ERROR,
  538.                                   buttons=gtk.BUTTONS_CLOSE)
  539.             d.set_markup("<big><b>%s</b></big>\n\n%s" % (
  540.                 _("Could not install the selected language support"),
  541.                 _("This is perhaps a bug of this application. Please "
  542.                   "file a bug report at "
  543.                   "https://launchpad.net/bugs/bugs/+package/ against "
  544.                   "the 'language-selector' product.")))
  545.             d.set_title=("")
  546.             res = d.run()
  547.             d.destroy()
  548.             # something went pretty bad, re-get a cache
  549.             progress = GtkProgress(self.dialog_progress,
  550.                                    self.progressbar_cache,
  551.                                    self.window_main)
  552.             self._cache = apt.Cache(self._localeinfo, progress)
  553.             progress.hide()
  554.             res = False
  555.         return res
  556.  
  557.     def commitAllChanges(self):
  558.         """ 
  559.         commit helper, builds the commit lists, verifies it
  560.         
  561.         returns the number of install/removed packages
  562.         """
  563.         self.setSensitive(False)
  564.         # install the new packages (if any)
  565.         (inst_list, rm_list) = self.build_commit_lists()
  566.         if not self.verify_commit_lists(inst_list, rm_list):
  567.             d = gtk.MessageDialog(parent=self.window_main,
  568.                                   flags=gtk.DIALOG_MODAL,
  569.                                   type=gtk.MESSAGE_ERROR,
  570.                                   buttons=gtk.BUTTONS_CLOSE)
  571.             d.set_markup("<big><b>%s</b></big>\n\n%s" % (
  572.                 _("Could not install the full language support"),
  573.                 _("Usually this is related to an error in your "
  574.                   "software archive or software manager. Check your "
  575.                   "software preferences in the menu \"Adminstration\".")))
  576.             d.set_title("")
  577.             d.run()
  578.             d.destroy()
  579.             self.setSensitive(True)
  580.             return 0
  581.         #print "inst_list: %s " % inst_list
  582.         #print "rm_list: %s " % rm_list
  583.         self.commit(inst_list, rm_list)
  584.  
  585.         # write input method config
  586.         #self.writeInputMethodConfig()
  587.  
  588.         # write the system default language
  589.         if self.writeSystemDefaultLang():
  590.             # queue a restart of gdm (if it is runing) to make the new
  591.             # locales usable
  592.             gdmscript = "/etc/init.d/gdm"
  593.             if os.path.exists("/var/run/gdm.pid") and os.path.exists(gdmscript):
  594.                 self.runAsRoot(["invoke-rc.d","gdm","reload"])
  595.         self.setSensitive(True)
  596.         return len(inst_list)+len(rm_list)
  597.  
  598.     # obsolete
  599.     def on_button_ok_clicked(self, widget):
  600.         self.commitAllChanges()
  601.         gtk.main_quit()
  602.  
  603.     def on_button_apply_clicked(self, widget):
  604.         self.window_installer.hide()
  605.         if self.commitAllChanges() > 0:
  606.             self.updateLanguageView()
  607.         self.updateUserDefaultCombo()
  608.         self.updateSystemDefaultCombo()
  609.  
  610.     def _run_synaptic(self, lock, inst, rm, id):
  611.         # FIXME: use self.runAsRoot() here
  612.         msg = _("The list of available languages on the "
  613.                 "system has been updated.")
  614.         msg = msg.replace("'","\\'")
  615.         cmd = ["gksu", 
  616.                "--desktop", "/usr/share/applications/language-selector.desktop", 
  617.                "--",
  618.                "/usr/sbin/synaptic", "--hide-main-window",
  619.                "--non-interactive", 
  620.                "--parent-window-id", "%s" % (id),
  621.                "--finish-str", msg
  622.                ]
  623.         f = tempfile.NamedTemporaryFile()        
  624.         cmd.append("--set-selections-file")
  625.         cmd.append(f.name)
  626.         for s in inst:
  627.             f.write("%s\tinstall\n" % s)
  628.         for s in rm:
  629.             f.write("%s\tdeinstall\n" % s)
  630.         f.flush()
  631.         subprocess.call(cmd)
  632.         lock.release()
  633.  
  634.     def _run_synaptic_update(self, lock, id):
  635.         cmd = ["gksu", 
  636.                "--desktop", "/usr/share/applications/language-selector.desktop", 
  637.                "--",
  638.                "/usr/sbin/synaptic", "--hide-main-window",
  639.                "--parent-window-id", "%s" % (id),
  640.                "--non-interactive", "--update-at-startup"
  641.                ]
  642.         subprocess.call(cmd)
  643.         lock.release()
  644.  
  645.     def update(self):
  646.         " update the package lists via synaptic "
  647.         lock = thread.allocate_lock()
  648.         lock.acquire()
  649.         t = thread.start_new_thread(self._run_synaptic_update,(lock, self.window_main.window.xid))
  650.         while lock.locked():
  651.             while gtk.events_pending():
  652.                 gtk.main_iteration()
  653.             time.sleep(0.05)
  654.  
  655.     def commit(self, inst, rm):
  656.         # unlock here to make sure that lock/unlock are always run
  657.         # pair-wise (and don't explode on errors)
  658.         if len(inst) == 0 and len(rm) == 0:
  659.             return
  660.         lock = thread.allocate_lock()
  661.         lock.acquire()
  662.         t = thread.start_new_thread(self._run_synaptic,(lock,inst,rm, self.window_main.window.xid))
  663.         while lock.locked():
  664.             while gtk.events_pending():
  665.                 gtk.main_iteration()
  666.             time.sleep(0.05)
  667.  
  668.     def on_button_cancel_clicked(self, widget):
  669.         #print "button_cancel"
  670.         self.window_installer.hide()
  671.  
  672.     def on_delete_event(self, event, data):
  673.         if self.window_main.get_property("sensitive") is False:
  674.             return True
  675.         else:
  676.             gtk.main_quit()
  677.  
  678.     def verifyInstalledLangPacks(self):
  679.         """ called at the start to inform about possible missing
  680.             langpacks (e.g. gnome/kde langpack transition)
  681.         """
  682.         #print "verifyInstalledLangPacks"
  683.         missing = self.getMissingLangPacks()
  684.  
  685.         #print "Missing: %s " % missing
  686.         if len(missing) > 0:
  687.             # FIXME: add "details"
  688.             d = gtk.MessageDialog(parent=self.window_main,
  689.                                   flags=gtk.DIALOG_MODAL,
  690.                                   type=gtk.MESSAGE_QUESTION)
  691.             d.set_markup("<big><b>%s</b></big>\n\n%s" % (
  692.                 _("The language support is not installed completely"),
  693.                 _("Some translations or writing aids available for your "
  694.                   "chosen languages are not installed yet. Do you want "
  695.                   "to install them now?")))
  696.             d.add_buttons(_("_Remind Me Later"), gtk.RESPONSE_NO,
  697.                           _("_Install"), gtk.RESPONSE_YES)
  698.             d.set_default_response(gtk.RESPONSE_YES)
  699.             d.set_title("")
  700.             expander = gtk.Expander(_("Details"))
  701.             scroll = gtk.ScrolledWindow()
  702.             scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
  703.             textview = gtk.TextView()
  704.             textview.set_cursor_visible(False)
  705.             textview.set_editable(False)
  706.             buf = textview.get_buffer()
  707.             pkgs = ""
  708.             for pkg in missing:
  709.                 pkgs += "%s\n" % pkg
  710.             buf.set_text(pkgs)
  711.             buf.place_cursor(buf.get_start_iter())
  712.             expander.add(scroll)
  713.             scroll.add(textview)
  714.             d.vbox.pack_start(expander)
  715.             expander.show_all()
  716.             res = d.run()
  717.             d.destroy()
  718.             if res == gtk.RESPONSE_YES:
  719.                 self.setSensitive(False)
  720.                 self.commit(missing, [])
  721.                 self.updateLanguageView()
  722.                 self.setSensitive(True)
  723.  
  724.     def updateLanguageView(self):
  725.         #print "updateLanguageView()"
  726.         self._langlist.clear()
  727.  
  728.         progress = GtkProgress(self.dialog_progress, self.progressbar_cache,
  729.                                self.window_main)
  730.         try:
  731.             self.openCache(progress)
  732.             progress.hide()
  733.         except ExceptionPkgCacheBroken:
  734.             d = gtk.MessageDialog(parent=self.window_main,
  735.                                   flags=gtk.DIALOG_MODAL,
  736.                                   type=gtk.MESSAGE_ERROR,
  737.                                   buttons=gtk.BUTTONS_CLOSE)
  738.             d.set_markup("<big><b>%s</b></big>\n\n%s" % (
  739.                 _("Software database is broken"),
  740.                 _("It is impossible to install or remove any software. "
  741.                   "Please use the package manager \"Synaptic\" or run "
  742.                   "\"sudo apt-get install -f\" in a terminal to fix "
  743.                   "this issue at first.")))
  744.             d.set_title("")
  745.             d.run()
  746.             d.destroy()
  747.             sys.exit(1)
  748.  
  749.         languageList = self._cache.getLanguageInformation()
  750.         #print "ll size: ", len(languageList)
  751.         #print "ll type: ", type(languageList)
  752.         for lang in languageList:
  753.             #print "langInfo: %s" % lang
  754.             inconsistent = lang.inconsistent
  755.             #if inconsistent:
  756.             #    print "inconsistent", lang.language
  757.             installed = lang.fullInstalled
  758.             self._langlist.append([_(lang.language), lang])
  759.         self._langlist.set_sort_column_id(LIST_LANG, gtk.SORT_ASCENDING)
  760.         for button in ( 
  761.               "checkbutton_basic_translations",
  762.               "checkbutton_extra_translations",
  763.               "checkbutton_writing_aids",
  764.               "checkbutton_input_methods",
  765.               "checkbutton_extra",
  766.               "checkbutton_fonts"):
  767.             self.block_toggle = True
  768.             getattr(self, button).set_active(False)
  769.             getattr(self, button).set_sensitive(False)
  770.             self.block_toggle = False
  771.  
  772.     def writeSystemDefaultLang(self):
  773.         combo = self.combobox_system_language
  774.         model = combo.get_model()
  775.         if combo.get_active() < 0:
  776.             return
  777.         (lang, code) = model[combo.get_active()]
  778.         old_code = self._localeinfo.getDefaultLanguage()
  779.         # no changes, nothing to do
  780.         if old_code == code:
  781.             return False
  782.         self.setSystemDefaultLanguage(code)
  783.         return True
  784.  
  785.     def writeUserDefaultLang(self):
  786.         combo = self.combobox_user_language
  787.         model = combo.get_model()
  788.         if combo.get_active() < 0:
  789.             return
  790.         (lang, code) = model[combo.get_active()]
  791.         temp = self.getUserDefaultLanguage()
  792.         if temp == None:
  793.             old_code = self._localeinfo.getDefaultLanguage()
  794.         else:
  795.             old_code = temp.split("\.")[0]
  796.         # no changes, nothing to do
  797.         if old_code == code:
  798.             return False
  799.         self.setUserDefaultLanguage(code)
  800.         return True
  801.  
  802.     @blockSignals
  803.     def updateSystemDefaultCombo(self):
  804.         #print "updateSystemDefault()"
  805.         combo = self.combobox_system_language
  806.         cell = combo.get_child().get_cell_renderers()[0]
  807.         # FIXME: use something else than a hardcoded value here
  808.         cell.set_property("wrap-width",300)
  809.         cell.set_property("wrap-mode",pango.WRAP_WORD)
  810.         model = combo.get_model()
  811.         model.clear()
  812.  
  813.         # find the default
  814.         defaultLangName = None
  815.         defaultLangCode = self.getSystemDefaultLanguage()
  816.         if defaultLangCode:
  817.             defaultLangName = self._localeinfo.translate(defaultLangCode)
  818.  
  819.         # find out about the other options        
  820.         for (i, locale) in enumerate(self._localeinfo.generated_locales()):
  821.             iter = model.append()
  822.             model.set(iter,
  823.                       COMBO_LANGUAGE,self._localeinfo.translate(locale),
  824.                       COMBO_CODE, locale)
  825.             if (defaultLangName and
  826.                    self._localeinfo.translate(locale) == defaultLangName):
  827.                 combo.set_active(i)
  828.  
  829.         # reset the state of the apply button
  830.         self.combo_syslang_dirty = False
  831.         self.check_status()
  832.  
  833.     # FIXME: updateUserDefaultCombo and updateSystemDefaultCombo
  834.     #        duplicate too much code
  835.     @blockSignals
  836.     def updateUserDefaultCombo(self):
  837.         #print "updateUserDefault()"
  838.         combo = self.combobox_user_language
  839.         cell = combo.get_child().get_cell_renderers()[0]
  840.         # FIXME: use something else than a hardcoded value here
  841.         cell.set_property("wrap-width",300)
  842.         cell.set_property("wrap-mode",pango.WRAP_WORD)
  843.         model = combo.get_model()
  844.         model.clear()
  845.  
  846.         # find the default
  847.         defaultLangName = None
  848.         defaultLangCode = self.getUserDefaultLanguage()
  849.         if defaultLangCode == None:
  850.             defaultLangCode = self.getSystemDefaultLanguage()
  851.         if defaultLangCode:
  852.             defaultLangName = self._localeinfo.translate(defaultLangCode)
  853.  
  854.         # find out about the other options        
  855.         for (i, locale) in enumerate(self._localeinfo.generated_locales()):
  856.             iter = model.append()
  857.             model.set(iter,
  858.                       COMBO_LANGUAGE,self._localeinfo.translate(locale),
  859.                       COMBO_CODE, locale)
  860.             if (defaultLangName and 
  861.                    self._localeinfo.translate(locale) == defaultLangName):
  862.                 combo.set_active(i)
  863.             
  864.         # reset the state of the apply button
  865.         self.combo_userlang_dirty = False
  866.         self.check_status()
  867.     
  868.     def on_treeview_languages_row_activated(self, treeview, path, view_column):
  869.         self.on_toggled(None,str(path[0]))
  870.